package service

import (
	"context"
	"encoding/json"
	"fmt"
	grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
	"golang.org/x/sync/errgroup"
	"google.golang.org/grpc"
	"net"
	"os"
	"os/signal"
	"syscall"
	pb "week13/api/proto"
	"week13/cmd"
	"week13/configs"
	"week13/errors"
	"week13/internal/biz/deal"
	"week13/internal/biz/income"
	"week13/internal/biz/item"
	"week13/log"
	"week13/metrics"
)

type AssetService struct {

}
//创建订单
func (asset *AssetService) CreateDeal(ctx context.Context, in *pb.Deal) (*pb.DealResponse, error) {
	if in.ItemId <1 || in.AgentId<1 || in.GenTime<0 || in.PayType == 0|| in.FromEndPoint <1 {
		return nil, errors.NewIllegalParam("createDeal params error")
	}
	dto := deal.DealDTO{
		DealId: 0,
		AgentId: in.AgentId,
		ItemId: in.ItemId,
		GenTime: int(in.GenTime),
		PayType: int(in.PayType),
		FromEndPoint: int(in.FromEndPoint),
	}
	var result *pb.DealResponse = &pb.DealResponse{}
	newDeal, err := deal.CreateDeal(dto)
	if err != nil {
		log.Error("create deal err:",err.Error())
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/CreateDeal",result.Code)
		return result,nil
	}
	jsonData,err := json.Marshal(newDeal.DTO)
	if err != nil {
		fmt.Printf("%s,%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/CreateDeal",result.Code)
		return result,nil
	}
	pdeal := &pb.Deal{}
	err = json.Unmarshal(jsonData,pdeal)
	if err != nil {
		fmt.Printf("%s,%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/asset/CreateDeal",result.Code)
		return result,nil
	}
	result.Data =pdeal
	return result,nil
}
//获取订单信息
func (asset *AssetService) Deal(ctx context.Context, in *pb.DealRequest) (*pb.DealResponse, error){
	agentId := ctx.Value("agentId").(int64)
	if in.DealId <1 && agentId < 1 {
		return nil, errors.NewIllegalParam("deal params error")
	}
	data, err := deal.FindOne(deal.DealDTO{DealId: in.DealId,AgentId: agentId})
	var result *pb.DealResponse = &pb.DealResponse{}
	if err != nil {
		log.Error("get deal err:%",err.Error())
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/Deal",result.Code)
		return result,nil
	}
	jsonData,err := json.Marshal(data)
	if err != nil {
		log.Info("deal json transfer  data:%s, err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Deal",result.Code)
		return result,nil
	}
	pdeal := &pb.Deal{}
	err = json.Unmarshal(jsonData,pdeal)
	if err != nil {
		log.Info("deal json transfer  data:%s, err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Deal",result.Code)
		return result,nil
	}
	result.Data =pdeal
	return result,nil
}
//订单列表
func (asset *AssetService) Deals(ctx context.Context, in *pb.DealRequest) (*pb.DealsResponse, error){
	return nil,nil
}
//收入
func (asset *AssetService) Income(ctx context.Context, in *pb.IncomeRequset) (*pb.IncomeResponse, error){
	agentId := ctx.Value("agentId").(int64)
	var err error
	var result  *pb.IncomeResponse = &pb.IncomeResponse{}
	if in.DealId <1 && agentId  < 1 && in.IncomeId<1 {
		err = errors.NewIllegalParam("income params error")
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/income",result.Code)
		return result, nil
	}
	data, err := income.FindOne(income.IncomeDTO{DealId: in.DealId,AgentId: agentId ,Id: in.IncomeId})
	if err != nil {
		log.Error("get income err:",err.Error())
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/income",result.Code)
		return result, nil
	}
	jsonData,err := json.Marshal(data)
	if err != nil {
		log.Info("transfer json data:%s,err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Income",result.Code)
		return result,nil
	}
	pIncome := &pb.Income{}
	err = json.Unmarshal(jsonData,pIncome)
	if err != nil {
		log.Info("transfer json data:%s,err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Income",result.Code)
		return result,nil
	}
	result.Data = pIncome
	return result,nil
}
//收入列表
func (asset *AssetService) Incomes(ctx context.Context, in *pb.IncomeRequset) (*pb.IncomesResponse, error){
	agentId := ctx.Value("agentId").(int64)
	var err error
	var result  *pb.IncomesResponse = &pb.IncomesResponse{}
	if in.DealId <1 && agentId < 1 && in.IncomeId<1 {
		err = errors.NewIllegalParam("incomes params error")
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/Incomes",result.Code)
		return result, nil
	}
	data,ct, err := income.List(income.IncomeDTO{DealId: in.DealId,AgentId: agentId,Id: in.IncomeId},int(in.Page),int(in.PageSize))

	if err != nil {
		log.Error("incomes err:%s",err.Error())
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/Incomes",result.Code)
		return result, err
	}
	incomes := pb.Incomes{}
	if ct == 0 {
		return result,nil
	}
	jsonData,err := json.Marshal(data)
	if err != nil {
		log.Info("transfer json data:%s,err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Incomes",result.Code)
		return result,nil
	}
	pIncomes := make([]*pb.Income,0)
	err = json.Unmarshal(jsonData,&pIncomes)
	if err != nil {
		log.Info("transfer json data:%s,err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Incomes",result.Code)
		return result,nil
	}
	incomes.Count = int32(ct)
	incomes.List = pIncomes
	result.Data = &incomes
	return result,nil
}
//商品
func (asset *AssetService) Item(ctx context.Context, in *pb.ItemRequest) (*pb.ItemResponse, error){
	var err error
	var result  *pb.ItemResponse = &pb.ItemResponse{}
	if in.ItemId <1 && in.Name == ""  {
		err = errors.NewIllegalParam("item params error")
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/Item",result.Code)
		return result, nil
	}
	data, err := item.FindOne(item.ItemDTO{ItemId: int(in.ItemId),ItemName: in.Name})
	if err != nil {
		log.Error("get item err:",err.Error())
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/Item",result.Code)
		return result, err
	}
	jsonData,err := json.Marshal(data)
	if err != nil {
		log.Info("transfer json data:%s,err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Item",result.Code)
		return result,nil
	}
	pItem := &pb.Item{}
	err = json.Unmarshal(jsonData,pItem)
	if err != nil {
		log.Info("transfer json data:%s,err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Item",result.Code)
		return result,nil
	}
	result.Data = pItem
	return result,nil
}
//商品列表
func (asset *AssetService) Items(ctx context.Context, in *pb.ItemRequest) (*pb.ItemsResponse, error){
	var err error
	var result  *pb.ItemsResponse = &pb.ItemsResponse{}
	if in.ItemId <1 && in.Name == ""  {
		err = errors.NewIllegalParam("item params error")
		return result, nil
	}
	data,ct, err := item.List(item.ItemDTO{ItemId: int(in.ItemId),ItemName: in.Name},int(in.Page),int(in.PageSize))
	if err != nil {
		log.Error("items err:%s",err.Error())
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/items",result.Code)
		return nil, err
	}
	items := pb.Items{}
	if ct == 0 {
		return result,nil
	}
	jsonData,err := json.Marshal(data)
	if err != nil {
		log.Info("transfer json data:%s,err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Items",result.Code)
		return result,nil
	}
	pItems := make([]*pb.Item,0)
	err = json.Unmarshal(jsonData,&pItems)
	if err != nil {
		log.Info("transfer json data:%s,err:%s",jsonData,err.Error())
		result.Code = errors.JSON_FAIL
		result.Message = errors.JSON_FAIL_MSG
		metrics.IncrServerRequest("asset/Items",result.Code)
		return result,nil
	}
	items.Count = int32(ct)
	items.List = pItems
	result.Data = &items
	return result,nil
}
//订单信息
func (asset *AssetService) DealInfo(ctx context.Context, in *pb.DealRequest) (*pb.DealInfoResponse, error){
	var err error
	var result  *pb.DealInfoResponse = &pb.DealInfoResponse{}
	agentId := ctx.Value("agentId").(int64)
	if in.DealId <1  {
		err = errors.NewIllegalParam("deal params error")
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/DealInfo",result.Code)
		return result, nil
	}
	data, err := deal.FindOne(deal.DealDTO{DealId: in.DealId,AgentId: agentId})
	if err != nil {
		log.Error("get dealInfo err:%s",err.Error())
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/DealInfo",result.Code)
		return nil, err
	}
	jsonData,_ := json.Marshal(data)
	pdeal := &pb.Deal{}
	json.Unmarshal(jsonData,pdeal)
	dealInfo := pb.DealInfo{Deal:pdeal}

	group := new(errgroup.Group)
	incomeFun := func() error{
		data, err := income.FindOne(income.IncomeDTO{DealId: in.DealId})
		if err != nil {
			return err
		}
		jsonData,_ := json.Marshal(data)
		pIncome := &pb.Income{}
		err = json.Unmarshal(jsonData,pIncome)

		if err != nil {
			return  err
		}
		dealInfo.Income = pIncome
		return nil
	}
	itemFun := func() error{
		data, err := item.FindOne(item.ItemDTO{ItemId: int(pdeal.ItemId)})
		if err != nil {
			return err
		}
		jsonData,_ := json.Marshal(data)
		pItem := &pb.Item{}
		err = json.Unmarshal(jsonData,pItem)
		if err != nil {
			return  err
		}
		dealInfo.Item = pItem
		return nil
	}
	group.Go(incomeFun)
	group.Go(itemFun)
	if err = group.Wait(); err != nil {
		log.Error("get dealInfo err:",err.Error())
		result.Code = errors.Code(err)
		result.Message = errors.Message(err)
		metrics.IncrServerRequest("asset/DealInfo",result.Code)
		return result,nil
	}
	return result,nil
}


type AssetServer struct {
	stop chan int
	signs chan os.Signal
	config configs.AppConfig
}

func (srv *AssetServer) Run(ctx context.Context) error {
	listener, err := net.Listen("tcp", srv.config.Addr)
	if err != nil {
		log.Error("asset net.listen err:%v", err)
		return err
	}
	AuthFunc := cmd.AuthFunc()
	log.Info(" asset net listening %s",srv.config.Addr)
	rpcServer := grpc.NewServer(
		grpc.StreamInterceptor(grpc_auth.StreamServerInterceptor(AuthFunc)),
		grpc.UnaryInterceptor(grpc_auth.UnaryServerInterceptor(AuthFunc)),
	)
	pb.RegisterAssetSrvServer(rpcServer,&AssetService{})
	signal.Notify(srv.signs, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		select {
		case <-srv.stop:
			rpcServer.Stop()
		case <-srv.signs:
			rpcServer.Stop()
		case <-ctx.Done():
			rpcServer.Stop()
		}
	}()
	fmt.Println("asset agent server:",srv.config.Addr)
	err = rpcServer.Serve(listener)
	log.Error("asset grpc server err: %v", err)
	return err
}
func (srv *AssetServer) Close()  {
	close(srv.stop)
}
func NewAssetServer(config configs.AppConfig) *AssetServer{
	server := &AssetServer{}
	server.stop = make(chan int, 1)
	server.signs = make(chan os.Signal, 1)
	server.config = config
	return server
}